package com.corecloud.security;

import com.corecloud.entity.SysLogEntity;
import com.corecloud.mapper.mysql.SysLogMapper;
import com.corecloud.service.SysUserService;
import com.corecloud.tools.MD5Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 认证提供者、校验用户、登录名密码、
 * 查验当前用户登录次数，次数过多加以限制、
 * 以及向系统提供一个用户信息的综合封装
 */
@Component
public class DefaultAuthenticationProvider implements AuthenticationProvider {
	@Autowired
	private UserDetailsService userDetailsService;
	@Autowired
	private SysLogMapper sysLogMapper;
	@Autowired
	private SysUserService sysUserService;
	@Autowired
	private RedisTemplate redisTemplate;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		Date nowDate = new Date();
//		获取用户IP地址
		WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();

//		登录输入的信息
		String username = (String) authentication.getPrincipal();
		String password = (String) authentication.getCredentials();
		String remoteAddressIp = details.getRemoteAddress();

//		根据用户名查询当前用户状态信息
		Integer sysUserState = (Integer) redisTemplate.boundHashOps("LoseEfficacy:"+username).get(username);
//		查询当前用户是否为锁定状态
		if (sysUserState != null && sysUserState.equals(0)){
			throw new UsernameNotFoundException("用户登录受限，请联系管理员或24小时后解锁！");
		}

//		登陆登陆留验记录、判断当前登录10分钟内的次数
		String s = loginInterceptPage(username, nowDate.getTime());

		if ("1".equals(s)){
			//插入登录日志
			SysLogEntity sysLog = new SysLogEntity();
			sysLog.setUrl("/login");
			sysLog.setUserName(username);
			sysLog.setCreateTime(new Date());
			sysLog.setIp(remoteAddressIp);

			//用户信息合法性认证
			UserDetails userDetails = userDetailsService.loadUserByUsername(username);
			if (userDetails == null) {
				sysLog.setMsg("用户不存在");
				sysLogMapper.insert(sysLog);
				throw new UsernameNotFoundException("用户不存在");
			}

			//比对密码
			String pwd = userDetails.getPassword();
			String encodePassword = MD5Utils.encodeByMD5(password,"{1#2$3%4(5)6@7!poeeww$3%4(5)djjkkldss}");
			if (!encodePassword.equals(pwd)) {
				sysLog.setMsg("密码不正确");
				sysLogMapper.insert(sysLog);
				throw new BadCredentialsException("密码不正确");
			}
			sysLog.setMsg("登录成功");
			sysLogMapper.insert(sysLog);

			//授权信息
			Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();

			return new UsernamePasswordAuthenticationToken(userDetails, password, authorities);
		}else {
			throw new UsernameNotFoundException("用户登录受限，请联系管理员或24小时后解锁！");
		}

	}

	@Override
	public boolean supports(Class<?> authentication) {
		return true;
	}


	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	/**
	 * 登陆登陆留验记录
	 * @return
	 */
	public String loginInterceptPage(String username,long date){
		Set sysUserState = redisTemplate.keys(username+":*");
		if (sysUserState.size() < 6){
//			添加用户登录记录
			redisTemplate.boundHashOps(username +":"+date).put(username, 1);
//			用户缓存有效时间
			redisTemplate.boundValueOps(username +":"+date).expire(10, TimeUnit.MINUTES);
			return "1";
		}else {
//			添加用户登录记录并修改用户状态为关闭
			redisTemplate.boundHashOps("LoseEfficacy:"+username).put(username, 0);
			redisTemplate.boundValueOps("LoseEfficacy:"+username).expire(24, TimeUnit.HOURS);
			return "0";
		}
	}

	/**
	 * 修改用户是否启用的状态
	 * @param username
	 * @param date
	 */
	public void setUserIsValid(String username, Date date, Integer isValid){
		Map<String, Object> mapUserIsValid = new HashMap<>();
		mapUserIsValid.put("userName",username);
//		mapUserIsValid.put("noValidTime",date);
		mapUserIsValid.put("isValid",isValid);
		sysUserService.updateUserIsValid(mapUserIsValid);
	}

}
